package com.askey.bitratedemo;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.graphics.Color;
import android.hardware.camera2.CameraCharacteristics;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.util.Log;
import android.view.View;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;

import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.ArrayList;

public class BitrateChartActivity extends AppCompatActivity implements VideoEncoder.OnMediaFormatReadyListener, VideoEncoder.OutputDataCallback, View.OnClickListener {

    private VideoEncoder.EncoderConfig mConfig;
    private VideoEncoder mEncoder;
    private CAMERA mCam;
    private volatile ArrayList<Entry> mEntries;
    private LineChart mChart;
    private LineDataSet mDataSet;
    private ArrayList<Entry> mEntriesAvg;
    private LineDataSet mDatasetAvg;
    private ArrayList<ILineDataSet> mSets;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bitrate);
        findViewById(R.id.btn_stop).setOnClickListener(this);

        parseIntent();

        mEntries = new ArrayList<Entry>();
        mEntriesAvg = new ArrayList<Entry>();
        mDatasetAvg = new LineDataSet(mEntriesAvg, "Avg");
        mDatasetAvg.setDrawValues(false);
        mDatasetAvg.setDrawCircleHole(false);
        mDatasetAvg.setDrawCircles(false);
        mDatasetAvg.setColor(Color.MAGENTA);

        mChart = (LineChart) findViewById(R.id.chart);

        Description desc = new Description();
        desc.setText(mConfig.toString());
        desc.setTextSize(20);

        mDataSet = new LineDataSet(mEntries, "Real-Time");
        mDataSet.setDrawValues(false);
        mDataSet.setDrawCircleHole(false);
        mDataSet.setDrawCircles(false);

        mSets = new ArrayList<>();
        mSets.add(mDataSet);
        mSets.add(mDatasetAvg);

        LineData lineData = new LineData(mSets);
        mChart.setBackgroundColor(Color.WHITE);
        mChart.setDescription(desc);
        mChart.setDrawGridBackground(false);
        mChart.setGridBackgroundColor(Color.WHITE);
        mChart.getXAxis().setEnabled(false);
        mChart.getAxisRight().setEnabled(false);
        {
            LimitLine yLimit = new LimitLine(mConfig.bitrate / 1024f, mConfig.bitrate / 1024 + " kb/s");
            yLimit.setLineWidth(2f);
            yLimit.enableDashedLine(10f, 10f, 0f);
            yLimit.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_BOTTOM);
            yLimit.setTextSize(10f);
            mChart.getAxisLeft().addLimitLine(yLimit);
        }
        mChart.setData(lineData);
        mChart.invalidate();

        mainJob();
    }

    private void parseIntent() {
        Intent i = getIntent();
        mConfig = new VideoEncoder.EncoderConfig();
        mConfig.type = MediaFormat.MIMETYPE_VIDEO_AVC;
        mConfig.width = i.getIntExtra("w", 1920);
        mConfig.height = i.getIntExtra("h", 1080);
        mConfig.framerate = i.getIntExtra("fr", 27);
        mConfig.bitrate = i.getIntExtra("br", 1) * 1024;
        int mode = i.getIntExtra("mode", 1);
        if (mode == 0) {
            mConfig.mode = MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR;
        } else if (mode == 1) {
            mConfig.mode = MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR;
        } else {
            mConfig.mode = MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ;
        }

        Log.d("BitrateChartActivity", mConfig.toString());
    }

    private void mainJob() {
        mEncoder = new VideoEncoder(mConfig, this);
        mEncoder.setOutputDataListener(this);
        mEncoder.prepare();

        mCam = new CAMERA(CameraCharacteristics.LENS_FACING_BACK, mEncoder.getSurface(), this);
        mCam.start();
    }

    @Override
    public void onMediaFormatReady(MediaFormat format) {

    }


    private long lastTime = 0L;
    private long dataSize = 0L;
    private long dataSizeTotal = 0L;
    private int count = 1;

    @Override
    public void onDataAvailable(ByteBuffer bb, MediaCodec.BufferInfo info) {
        long timeStamp = System.currentTimeMillis();
        dataSize += info.size * 8;

        if (timeStamp - lastTime >= 1000) {
            float bitrate = dataSize / 1024;
            dataSizeTotal += bitrate;

            LineData lineData = mChart.getLineData();
            LineDataSet dataSet = (LineDataSet) lineData.getDataSetByIndex(0);
            mEntries.add(new Entry(count, bitrate));
            dataSet.setValues(mEntries);
            dataSet.setLabel("Real-Time: " + bitrate);
            dataSet.notifyDataSetChanged();

            LineDataSet dataSetAvg = (LineDataSet) lineData.getDataSetByIndex(1);
            mEntriesAvg.add(new Entry(count, dataSizeTotal / count));
            dataSetAvg.setValues(mEntriesAvg);
            dataSetAvg.setLabel(String.format("Avg: %.2fMB / %ds = %d", dataSizeTotal / 1024f / 8, count, dataSizeTotal / count));
            dataSetAvg.notifyDataSetChanged();

            mChart.getData().notifyDataChanged();
            mChart.notifyDataSetChanged();
            mChart.invalidate();

            Log.w("BitrateChartActivity", String.format("Bitrate: %.2f kb/s", bitrate));
            lastTime = timeStamp;
            dataSize = 0L;
            count++;
        }
    }

    @Override
    public void onClick(View view) {
        if (mCam != null)
            mCam.stop();
        finish();
    }
}
